import logging
import numpy as np
from typing import Dict, List, Any, Optional
from datetime import datetime, timedelta

class UserRecommender:
    """
    用户推荐器，根据用户偏好推荐内容
    """
    
    def __init__(self, db_manager):
        """
        初始化用户推荐器
        
        Args:
            db_manager: 数据库管理器
        """
        self.logger = logging.getLogger("recommender.user")
        self.db_manager = db_manager
    
    def get_recommendations(self, user_id: str, limit: int = 20) -> List[Dict[str, Any]]:
        """
        获取针对特定用户的推荐
        
        Args:
            user_id: 用户ID
            limit: 返回数量限制
            
        Returns:
            推荐内容列表
        """
        # 获取用户信息
        user = self._get_user(user_id)
        if not user:
            self.logger.warning(f"User {user_id} not found")
            return []
            
        # 获取用户兴趣和历史
        interests = user.get('interests', [])
        view_history = user.get('view_history', [])
        
        # 基于兴趣的推荐
        interest_recs = self._recommend_by_interests(interests, view_history, limit)
        
        # 基于历史的推荐
        history_recs = self._recommend_by_history(view_history, limit)
        
        # 热门内容推荐（兜底）
        popular_recs = self._recommend_popular(view_history, limit)
        
        # 合并推荐结果，去重
        all_recs = []
        seen_ids = set()
        
        # 优先添加基于兴趣的推荐
        for item in interest_recs:
            item_id = item.get('id') or item.get('_id')
            if item_id and item_id not in seen_ids:
                seen_ids.add(item_id)
                item['recommend_reason'] = '基于您的兴趣'
                all_recs.append(item)
        
        # 然后添加基于历史的推荐
        for item in history_recs:
            item_id = item.get('id') or item.get('_id')
            if item_id and item_id not in seen_ids:
                seen_ids.add(item_id)
                item['recommend_reason'] = '与您最近查看内容相似'
                all_recs.append(item)
        
        # 最后添加热门内容
        for item in popular_recs:
            item_id = item.get('id') or item.get('_id')
            if item_id and item_id not in seen_ids:
                seen_ids.add(item_id)
                item['recommend_reason'] = '热门推荐'
                all_recs.append(item)
                
        # 如果推荐数量不足，添加最新内容
        if len(all_recs) < limit:
            latest_count = limit - len(all_recs)
            latest_recs = self._recommend_latest(view_history, latest_count)
            
            for item in latest_recs:
                item_id = item.get('id') or item.get('_id')
                if item_id and item_id not in seen_ids:
                    seen_ids.add(item_id)
                    item['recommend_reason'] = '最新内容'
                    all_recs.append(item)
        
        # 限制返回数量
        return all_recs[:limit]
    
    def _get_user(self, user_id: str) -> Optional[Dict[str, Any]]:
        """
        获取用户信息
        
        Args:
            user_id: 用户ID
            
        Returns:
            用户信息
        """
        query = {'_id': user_id}
        users = self.db_manager.get_items('users', query)
        
        if users and len(users) > 0:
            return users[0]
        return None
    
    def _recommend_by_interests(self, interests: List[str], view_history: List[str], limit: int) -> List[Dict[str, Any]]:
        """
        基于用户兴趣推荐
        
        Args:
            interests: 用户兴趣列表
            view_history: 用户浏览历史
            limit: 返回数量限制
            
        Returns:
            推荐内容列表
        """
        if not interests:
            return []
            
        # 构建查询条件
        query = {
            'topic_categories': {'$in': interests},
            'created_at': {'$gte': datetime.now() - timedelta(days=30)}
        }
        
        # 排除已浏览内容
        if view_history:
            query['_id'] = {'$nin': view_history}
            
        # 按热度和时间排序
        sort = [('popularity_score', -1), ('created_at', -1)]
        
        # 获取推荐
        recommendations = self.db_manager.get_items('news', query, sort, limit)
        
        # 如果新闻不足，再从论文中获取
        if len(recommendations) < limit and 'AI研究' in interests:
            papers_query = {
                'categories': {'$in': interests},
                'created_at': {'$gte': datetime.now() - timedelta(days=60)}
            }
            
            if view_history:
                papers_query['_id'] = {'$nin': view_history}
                
            papers_sort = [('citation_count', -1), ('created_at', -1)]
            
            papers = self.db_manager.get_items('papers', papers_query, papers_sort, limit - len(recommendations))
            recommendations.extend(papers)
            
        return recommendations
    
    def _recommend_by_history(self, view_history: List[str], limit: int) -> List[Dict[str, Any]]:
        """
        基于用户浏览历史推荐
        
        Args:
            view_history: 用户浏览历史
            limit: 返回数量限制
            
        Returns:
            推荐内容列表
        """
        if not view_history:
            return []
            
        # 获取最近浏览的5条内容
        recent_history = view_history[-5:]
        
        # 获取这些内容的详细信息
        history_items = []
        for item_id in recent_history:
            items = self.db_manager.get_items('news', {'_id': item_id})
            if items:
                history_items.extend(items)
            else:
                # 也可能是论文
                paper_items = self.db_manager.get_items('papers', {'_id': item_id})
                if paper_items:
                    history_items.extend(paper_items)
        
        if not history_items:
            return []
            
        # 提取历史内容的主题和类别
        history_topics = []
        history_categories = []
        
        for item in history_items:
            topics = item.get('topic_categories', [])
            if topics:
                history_topics.extend(topics)
                
            cats = item.get('categories', [])
            if cats:
                history_categories.extend(cats)
        
        # 去重
        history_topics = list(set(history_topics))
        history_categories = list(set(history_categories))
        
        # 构建查询条件
        query = {
            '$or': [
                {'topic_categories': {'$in': history_topics}},
                {'categories': {'$in': history_categories}}
            ],
            'created_at': {'$gte': datetime.now() - timedelta(days=30)}
        }
        
        # 排除已浏览内容
        if view_history:
            query['_id'] = {'$nin': view_history}
            
        # 按热度和时间排序
        sort = [('popularity_score', -1), ('created_at', -1)]
        
        # 获取推荐
        return self.db_manager.get_items('news', query, sort, limit)
    
    def _recommend_popular(self, view_history: List[str], limit: int) -> List[Dict[str, Any]]:
        """
        推荐热门内容
        
        Args:
            view_history: 用户浏览历史
            limit: 返回数量限制
            
        Returns:
            推荐内容列表
        """
        # 查询条件
        query = {
            'created_at': {'$gte': datetime.now() - timedelta(days=7)}
        }
        
        # 排除已浏览内容
        if view_history:
            query['_id'] = {'$nin': view_history}
            
        # 按热度排序
        sort = [('popularity_score', -1), ('created_at', -1)]
        
        # 获取热门内容
        return self.db_manager.get_items('news', query, sort, limit)
    
    def _recommend_latest(self, view_history: List[str], limit: int) -> List[Dict[str, Any]]:
        """
        推荐最新内容
        
        Args:
            view_history: 用户浏览历史
            limit: 返回数量限制
            
        Returns:
            推荐内容列表
        """
        # 查询条件
        query = {
            'created_at': {'$gte': datetime.now() - timedelta(days=3)}
        }
        
        # 排除已浏览内容
        if view_history:
            query['_id'] = {'$nin': view_history}
            
        # 按时间排序
        sort = [('created_at', -1)]
        
        # 获取最新内容
        return self.db_manager.get_items('news', query, sort, limit)
    
    def update_user_profile(self, user_id: str, viewed_item: Dict[str, Any]) -> bool:
        """
        更新用户画像
        
        Args:
            user_id: 用户ID
            viewed_item: 用户查看的内容
            
        Returns:
            更新是否成功
        """
        try:
            # 获取当前用户
            user = self._get_user(user_id)
            if not user:
                self.logger.warning(f"User {user_id} not found for profile update")
                return False
                
            # 获取内容ID
            item_id = viewed_item.get('id') or viewed_item.get('_id')
            if not item_id:
                return False
                
            # 更新浏览历史
            view_history = user.get('view_history', [])
            if item_id in view_history:
                # 如果已经在历史中，先移除
                view_history.remove(item_id)
            
            # 添加到末尾
            view_history.append(item_id)
            
            # 仅保留最近100条历史
            if len(view_history) > 100:
                view_history = view_history[-100:]
                
            user['view_history'] = view_history
            
            # 更新兴趣标签
            interests = user.get('interests', [])
            
            # 添加内容的主题和类别到兴趣中
            topic_categories = viewed_item.get('topic_categories', [])
            categories = viewed_item.get('categories', [])
            
            new_interests = list(set(interests + topic_categories + categories))
            user['interests'] = new_interests
            
            # 保存更新后的用户信息
            self.db_manager.save_items('users', [user])
            
            return True
            
        except Exception as e:
            self.logger.error(f"Error updating user profile: {str(e)}")
            return False
            
    def create_or_update_user(self, user_data: Dict[str, Any]) -> bool:
        """
        创建或更新用户
        
        Args:
            user_data: 用户数据
            
        Returns:
            操作是否成功
        """
        try:
            if 'username' not in user_data or not user_data['username']:
                return False
                
            # 设置默认值
            if 'created_at' not in user_data:
                user_data['created_at'] = datetime.now()
                
            if 'interests' not in user_data:
                user_data['interests'] = []
                
            if 'view_history' not in user_data:
                user_data['view_history'] = []
                
            # 保存用户
            self.db_manager.save_items('users', [user_data])
            return True
            
        except Exception as e:
            self.logger.error(f"Error creating/updating user: {str(e)}")
            return False